/*
 * Copyright 2006-2022 ahtelit.com, All Rights Reserved.
 */

package com.telit.firecommand.service.impl;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.core.util.StrUtil;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.telit.android.entity.AppUserLocation;
import com.telit.android.feign.RemoteAndroidService;
import com.telit.common.constant.RoleCodeConstants;
import com.telit.common.core.utils.BaseEnum;
import com.telit.common.core.utils.FeignUtils;
import com.telit.common.entity.DataReturn;
import com.telit.common.entity.PageData;
import com.telit.common.enums.ResultCode;
import com.telit.common.exception.ForestBaseException;
import com.telit.common.util.LanguageUtils;
import com.telit.firecommand.dao.SysUserDAO;
import com.telit.firecommand.dao.SysUserRoleDAO;
import com.telit.firecommand.entity.SysUser;
import com.telit.firecommand.entity.SysUserRole;
import com.telit.firecommand.model.sysUser.UpdateUserRequest;
import com.telit.firecommand.service.SysUserRoleService;
import com.telit.firecommand.service.SysUserService;
import com.telit.firecommand.vo.ForesterVO;
import com.telit.firecommand.vo.MicroSysUserVO;
import com.telit.upms.dto.SysUserOperationStatusDto;
import com.telit.upms.feign.RemoteUpmsService;
import com.telit.upms.pojo.UserLockEnum;
import com.telit.upms.pojo.UserOperationEnum;
import com.telit.upms.vo.MicroSysUserAllInfoVo;
import com.telit.upms.vo.MicroSysUserVo;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.BeanUtils;
import org.springframework.stereotype.Service;

import java.util.*;
import java.util.function.Function;
import java.util.stream.Collectors;


/**
 * SysUserServiceImpl
 *
 * @author yuezhuang
 * @since 2023-01-17
 */
@Slf4j
@Service
@RequiredArgsConstructor
public class SysUserServiceImpl extends ServiceImpl<SysUserDAO, SysUser> implements SysUserService {

    private final SysUserDAO sysUserDAO;

    private final SysUserRoleDAO sysUserRoleDAO;

    private final SysUserRoleService sysUserRoleService;

    private final RemoteUpmsService remoteUpmsService;

    private final RemoteAndroidService remoteAndroidService;

    /**
     * 监听处理用户信息
     *
     * @param dto 用户信息
     */
    @Override
    public void dealSysUser(SysUserOperationStatusDto dto) {
        com.telit.common.core.utils.Result<Map<Long, MicroSysUserVo>> selectByBatchIdsResult = remoteUpmsService.selectByBatchIds(
                Collections.singletonList(dto.getUserId()), true);
        Map<Long, MicroSysUserVo> microSysUserVoMap = FeignUtils.unwrap(selectByBatchIdsResult);
        MicroSysUserVo microSysUserVo = microSysUserVoMap.get(dto.getUserId());
        if (microSysUserVo == null) {
            throw new ForestBaseException(
                    LanguageUtils.codeMessage(ResultCode.OPERATE_ERROR.getCode(), dto.getUserId()));
        }

        //查询用户角色信息
        com.telit.common.core.utils.Result<Map<Long, MicroSysUserAllInfoVo>> selectUserContainDeptAndRoleWithBatchIdsResult = remoteUpmsService.selectUserContainDeptAndRoleWithBatchIds(
                Collections.singletonList(dto.getUserId()), true);
        Map<Long, MicroSysUserAllInfoVo> longMicroSysUserAllInfoVoMap = FeignUtils.unwrap(
                selectUserContainDeptAndRoleWithBatchIdsResult);
        MicroSysUserAllInfoVo microSysUserAllInfoVo = longMicroSysUserAllInfoVoMap.get(dto.getUserId());
        if (microSysUserAllInfoVo == null) {
            throw new ForestBaseException(
                    LanguageUtils.codeMessage(ResultCode.OPERATE_ERROR.getCode(), dto.getUserId()));
        }

        UserOperationEnum userOperationEnum = BaseEnum.valueOf(UserOperationEnum.class, dto.getChangeCode());
        switch (userOperationEnum) {
            case ADD:
                SysUser sysUser = SysUser.builder()
                        .id(microSysUserVo.getId())
                        .customerId(microSysUserVo.getCustomerId())
                        .deptId(microSysUserVo.getDeptId())
                        .districtId(microSysUserVo.getDistrictId())
                        .userName(microSysUserVo.getUserName())
                        .realName(microSysUserVo.getRealName())
                        .passWord(microSysUserVo.getPassWord())
                        .birthday(microSysUserVo.getBirthday())
                        .idCard(microSysUserVo.getIdCard())
                        .officePhone(microSysUserVo.getOfficePhone())
                        .mobile(microSysUserVo.getMobile())
                        .email(microSysUserVo.getEmail())
                        .qq(microSysUserVo.getQq())
                        .wechat(microSysUserVo.getWechat())
                        .remark(microSysUserVo.getRemark())
                        .icon(null)
                        .responsibleZone(microSysUserVo.getResponsibleZone())
                        .position(microSysUserVo.getPosition())
                        .positionRank(microSysUserVo.getPositionRank())
                        .positionLevel(microSysUserVo.getPositionLevel())
                        .poorHousehold(microSysUserVo.getPoorHousehold())
                        .createTime(microSysUserVo.getCreateTime())
                        .createBy(microSysUserVo.getCreateBy())
                        .updateTime(microSysUserVo.getUpdateTime())
                        .updateBy(microSysUserVo.getUpdateBy())
                        .isDeleted(microSysUserVo.getIsDeleted())
                        .nativePlace(microSysUserVo.getNativePlace())
                        .jobNature(microSysUserVo.getJobNature())
                        .lastLoginTime(microSysUserVo.getLastLoginTime())
                        .duty(microSysUserVo.getDuty())
                        .isFirstLogin(microSysUserVo.getIsFirstLogin())
                        .remarkOne(microSysUserVo.getRemarkOne())
                        .remarkTwo(microSysUserVo.getRemarkTwo())
                        .remarkThree(microSysUserVo.getRemarkThree())
                        .avatar(microSysUserVo.getAvatar())
                        .address(microSysUserVo.getAddress())
                        .userOnlineStatus(0)
                        .districtCode(microSysUserAllInfoVo.getAreaCode())
                        .build();
                save(sysUser);

                update(Wrappers.<SysUser>lambdaUpdate()
                        .eq(SysUser::getId, dto.getUserId())
                        .set(SysUser::getIsShow,
                                microSysUserVo.getIsShow() != null ? microSysUserVo.getIsShow().getCode() : null)
                        .set(SysUser::getOnlineStatus,
                                microSysUserVo.getOnlineStatus() != null ? microSysUserVo.getOnlineStatus().getCode()
                                        : null)
                        .set(SysUser::getPoliticalStatus, microSysUserVo.getPoliticalStatus() != null
                                ? microSysUserVo.getPoliticalStatus().getCode() : null));

                sysUserRoleService.saveBatch(microSysUserAllInfoVo.getConvertList().stream().map(
                        microCustomRoleInfoVo -> SysUserRole.builder()
                                .userId(dto.getUserId())
                                .roleId(microCustomRoleInfoVo.getRoleId())
                                .build()).collect(Collectors.toList()));
                break;
            case UPDATE:
                SysUser updateSysUser = SysUser.builder()
                        .id(microSysUserVo.getId())
                        .customerId(microSysUserVo.getCustomerId())
                        .deptId(microSysUserVo.getDeptId())
                        .districtId(microSysUserVo.getDistrictId())
                        .userName(microSysUserVo.getUserName())
                        .realName(microSysUserVo.getRealName())
                        .passWord(microSysUserVo.getPassWord())
                        .birthday(microSysUserVo.getBirthday())
                        .idCard(microSysUserVo.getIdCard())
                        .officePhone(microSysUserVo.getOfficePhone())
                        .mobile(microSysUserVo.getMobile())
                        .email(microSysUserVo.getEmail())
                        .qq(microSysUserVo.getQq())
                        .wechat(microSysUserVo.getWechat())
                        .remark(microSysUserVo.getRemark())
                        .icon(null)
                        .responsibleZone(microSysUserVo.getResponsibleZone())
                        .position(microSysUserVo.getPosition())
                        .positionRank(microSysUserVo.getPositionRank())
                        .positionLevel(microSysUserVo.getPositionLevel())
                        .poorHousehold(microSysUserVo.getPoorHousehold())
                        .createTime(microSysUserVo.getCreateTime())
                        .createBy(microSysUserVo.getCreateBy())
                        .updateTime(microSysUserVo.getUpdateTime())
                        .updateBy(microSysUserVo.getUpdateBy())
                        .isDeleted(microSysUserVo.getIsDeleted())
                        .nativePlace(microSysUserVo.getNativePlace())
                        .jobNature(microSysUserVo.getJobNature())
                        .lastLoginTime(microSysUserVo.getLastLoginTime())
                        .duty(microSysUserVo.getDuty())
                        .isFirstLogin(microSysUserVo.getIsFirstLogin())
                        .remarkOne(microSysUserVo.getRemarkOne())
                        .remarkTwo(microSysUserVo.getRemarkTwo())
                        .remarkThree(microSysUserVo.getRemarkThree())
                        .avatar(microSysUserVo.getAvatar())
                        .address(microSysUserVo.getAddress())
                        .districtCode(microSysUserAllInfoVo.getAreaCode())
                        .build();
                updateById(updateSysUser);
                update(Wrappers.<SysUser>lambdaUpdate()
                        .eq(SysUser::getId, dto.getUserId())
                        .set(SysUser::getIsShow,
                                microSysUserVo.getIsShow() != null ? microSysUserVo.getIsShow().getCode() : null)
                        .set(SysUser::getOnlineStatus,
                                microSysUserVo.getOnlineStatus() != null ? microSysUserVo.getOnlineStatus().getCode()
                                        : null)
                        .set(SysUser::getPoliticalStatus, microSysUserVo.getPoliticalStatus() != null
                                ? microSysUserVo.getPoliticalStatus().getCode() : null));
                sysUserRoleService.remove(Wrappers.<SysUserRole>lambdaQuery().eq(
                        SysUserRole::getUserId, dto.getUserId()));
                sysUserRoleService.saveBatch(microSysUserAllInfoVo.getConvertList().stream().map(
                        microCustomRoleInfoVo -> SysUserRole.builder()
                                .userId(dto.getUserId())
                                .roleId(microCustomRoleInfoVo.getRoleId())
                                .build()).collect(Collectors.toList()));
                break;
            case RESET:
                update(Wrappers.<SysUser>lambdaUpdate()
                        .eq(SysUser::getId, microSysUserVo.getId())
                        .set(SysUser::getPassWord, microSysUserVo.getPassWord()));
                break;
            case REMOVE:
                update(Wrappers.<SysUser>lambdaUpdate()
                        .eq(SysUser::getId, microSysUserVo.getId())
                        .set(SysUser::getIsDeleted, 0));
                break;
            case CHANGE_START:
                update(Wrappers.<SysUser>lambdaUpdate()
                        .eq(SysUser::getId, dto.getUserId())
                        .set(SysUser::getIsLock, UserLockEnum.ENABLE.getCode()));
                break;
            case CHANGE_STOP:
                update(Wrappers.<SysUser>lambdaUpdate()
                        .eq(SysUser::getId, dto.getUserId())
                        .set(SysUser::getIsLock, UserLockEnum.DISABLE.getCode()));
                break;
            default:
                break;
        }
    }

    /**
     * 更新用户信息
     *
     * @param updateUserRequest 请求参数
     *
     * @return MicroSysUserAllInfoVo
     */
    @Override
    public MicroSysUserVO update(UpdateUserRequest updateUserRequest) {
        LambdaUpdateWrapper<SysUser> updateWrapper = Wrappers.lambdaUpdate();
        updateWrapper.eq(SysUser::getId, updateUserRequest.getUserId());
        if (StringUtils.isNotEmpty(updateUserRequest.getLatitude())) {
            updateWrapper.set(SysUser::getLatitude, updateUserRequest.getLatitude());
        }
        if (StringUtils.isNotEmpty(updateUserRequest.getLongitude())) {
            updateWrapper.set(SysUser::getLongitude, updateUserRequest.getLongitude());
        }
        if (updateUserRequest.getUserOnlineStatus() != null) {
            updateWrapper.set(SysUser::getUserOnlineStatus, updateUserRequest.getUserOnlineStatus());
        }
        int i = sysUserDAO.update(null, updateWrapper);
        if (i <= 0) {
            throw new ForestBaseException(LanguageUtils.codeMessage(ResultCode.OPERATION_ERROR.getCode()));
        }

        com.telit.common.core.utils.Result<Map<Long, MicroSysUserVo>> selectByBatchIdsResult = remoteUpmsService.selectByBatchIds(
                Collections.singletonList(updateUserRequest.getUserId()), true);
        Map<Long, MicroSysUserVo> microSysUserVoMap = FeignUtils.unwrap(selectByBatchIdsResult);
        MicroSysUserVo microSysUserVo = microSysUserVoMap.get(updateUserRequest.getUserId());
        if (microSysUserVo == null) {
            throw new ForestBaseException(
                    LanguageUtils.codeMessage(ResultCode.OPERATE_ERROR.getCode(), updateUserRequest.getUserId()));
        }

        MicroSysUserVO microSysUserVO = BeanUtil.copyProperties(microSysUserVo, MicroSysUserVO.class);
        microSysUserVO.setLatitude(updateUserRequest.getLatitude());
        microSysUserVO.setLongitude(updateUserRequest.getLongitude());
        microSysUserVO.setUserOnlineStatus(updateUserRequest.getUserOnlineStatus());

        return microSysUserVO;
    }

    /**
     * 查询人员列表
     *
     * @param onlineStatus  在线状态 0-离线 1-在线
     * @param name          护林员名称
     * @param regionCode    个人所属行政区划编码
     * @param areaRecursion 是否包含子行政区划数据
     * @param roleCodes     角色编码（使用英文逗号拼接）
     * @param userIds       id集合
     * @param current       当前页数
     * @param size          每页条数
     *
     * @return ForesterVO
     */
    @Override
    public PageData<List<ForesterVO>> qryList(Integer onlineStatus, String name, String regionCode,
                                              boolean areaRecursion, String roleCodes, String userIds, Integer current,
                                              Integer size) {
        List<Long> roleIds = new ArrayList<>();
        if (StringUtils.isNotEmpty(roleCodes)) {
            List<String> roleList = Arrays.asList(roleCodes.split(","));
            roleList.forEach(s -> {
                Long roleId = RoleCodeConstants.getRoleId(s);
                if (roleId != null) {
                    roleIds.add(roleId);
                }
            });
        }
        List<Long> userIdList = new ArrayList<>();
        if (StrUtil.isNotEmpty(userIds)) {
            String[] split = userIds.split(",");
            for (String s : split) {
                userIdList.add(Long.parseLong(s));
            }
        }
        Integer offset = (current - 1) * size;
        long total = sysUserDAO.count(onlineStatus, name, regionCode, areaRecursion, null, roleIds, userIdList);
        if (total == 0) {
            return PageData.<List<ForesterVO>>builder()
                    .count((int) total)
                    .size(size)
                    .current(current)
                    .datas(new ArrayList<>())
                    .build();
        }
        List<SysUser> sysUsers = sysUserDAO.selectByCondition(onlineStatus, name, regionCode, areaRecursion, null,
                roleIds, userIdList, size, offset);
        List<Long> ids = sysUsers.stream().map(SysUser::getId).collect(Collectors.toList());
        Map<Long, MicroSysUserAllInfoVo> longMicroSysUserAllInfoVoMap = batchGetUser(new ArrayList<>(ids), 200);
        
        //处理经纬度
        Map<Long, SysUser> longUserMap = sysUsers.stream().collect(
                Collectors.toMap(SysUser::getId, Function.identity(), (key1, key2) -> key2));
        //用户集合
        List<MicroSysUserAllInfoVo> microSysUserAllInfoVos = ids.stream().map(
                longMicroSysUserAllInfoVoMap::get).collect(Collectors.toList());
        List<ForesterVO> foresterVOList = new ArrayList<>();
        microSysUserAllInfoVos.stream().forEach(microSysUserAllInfoVo -> {
            ForesterVO foresterVO = new ForesterVO();
            BeanUtils.copyProperties(microSysUserAllInfoVo, foresterVO);
            //用户经纬度
            SysUser sysUser = longUserMap.get(foresterVO.getId());
            foresterVO.setLongitude(sysUser.getLongitude());
            foresterVO.setLatitude(sysUser.getLatitude());
            foresterVO.setUserOnlineStatus(sysUser.getUserOnlineStatus());
            foresterVOList.add(foresterVO);
        });

        return PageData.<List<ForesterVO>>builder()
                .count((int) total)
                .size(size)
                .current(current)
                .datas(foresterVOList)
                .build();
    }

    /**
     * 查询用户详情
     *
     * @param id id
     *
     * @return ForesterVO
     */
    @Override
    public ForesterVO qryDetail(Long id) {
        com.telit.common.core.utils.Result<Map<Long, MicroSysUserAllInfoVo>> selectUserContainDeptAndRoleWithBatchIdsResult = remoteUpmsService.selectUserContainDeptAndRoleWithBatchIds(
                Arrays.asList(id), true);
        Map<Long, MicroSysUserAllInfoVo> longMicroSysUserAllInfoVoMap = FeignUtils.unwrap(
                selectUserContainDeptAndRoleWithBatchIdsResult);
        MicroSysUserAllInfoVo microSysUserAllInfoVo = longMicroSysUserAllInfoVoMap.get(id);
        if (microSysUserAllInfoVo == null) {
            throw new ForestBaseException(LanguageUtils.codeMessage(ResultCode.OPERATE_ERROR.getCode(), id));
        }

        SysUser sysUser = sysUserDAO.selectByUserId(id);
        if (sysUser == null) {
            throw new ForestBaseException(LanguageUtils.codeMessage(ResultCode.OPERATE_ERROR.getCode(), id));
        }

        ForesterVO foresterVO = new ForesterVO();
        BeanUtils.copyProperties(microSysUserAllInfoVo, foresterVO);
        foresterVO.setLongitude(sysUser.getLongitude());
        foresterVO.setLatitude(sysUser.getLatitude());
        foresterVO.setUserOnlineStatus(sysUser.getUserOnlineStatus());
        foresterVO.setDistrictCode(sysUser.getDistrictCode());

        return foresterVO;
    }

    /**
     * 查询id集合
     *
     * @param onlineStatus  在线状态 0-离线 1-在线
     * @param name          护林员名称
     * @param regionCode    个人所属行政区划编码
     * @param areaRecursion 是否包含子行政区划数据
     * @param roleCodes     角色集合
     *
     * @return List<String>
     */
    @Override
    public List<Long> qryIdList(Integer onlineStatus, String name, String regionCode, boolean areaRecursion,
                                String roleCodes) {
        List<Long> roleIds = new ArrayList<>();
        if (StringUtils.isNotEmpty(roleCodes)) {
            List<String> roleList = Arrays.asList(roleCodes.split(","));
            roleList.forEach(s -> {
                Long roleId = RoleCodeConstants.getRoleId(s);
                if (roleId != null) {
                    roleIds.add(roleId);
                }
            });
        }

        List<SysUser> sysUsers = sysUserDAO.selectByCondition(onlineStatus, name, regionCode, areaRecursion, null,
                roleIds, null, Integer.MAX_VALUE, 0);

        return sysUsers.stream().map(SysUser::getId).collect(Collectors.toList());
    }

    @Override
    public void dealUserOnline() {
        //在线用户
        DataReturn<List<AppUserLocation>> listDataReturn = remoteAndroidService.onlineList();
        List<AppUserLocation> appUserLocations = listDataReturn.getData();
        Date now = new Date();
        if (CollectionUtil.isEmpty(appUserLocations)) {
            //将所有在线用户设置为离线
            LambdaUpdateWrapper<SysUser> sysUserLambdaUpdateWrapper = new LambdaUpdateWrapper<>();
            sysUserLambdaUpdateWrapper.eq(SysUser::getUserOnlineStatus, 1);
            sysUserLambdaUpdateWrapper.set(SysUser::getUserOnlineStatus, 0);
            sysUserLambdaUpdateWrapper.set(SysUser::getUpdateTime, now);
            sysUserDAO.update(null, sysUserLambdaUpdateWrapper);
        } else {
            List<Long> onlineUserIdList = appUserLocations.stream().map(AppUserLocation::getUserId).collect(
                    Collectors.toList());
            //设置在线状态
            LambdaUpdateWrapper<SysUser> onlineLambdaUpdateWrapper = new LambdaUpdateWrapper<>();
            onlineLambdaUpdateWrapper.in(SysUser::getId, onlineUserIdList);
            onlineLambdaUpdateWrapper.set(SysUser::getUserOnlineStatus, 1);
            onlineLambdaUpdateWrapper.set(SysUser::getUpdateTime, now);
            sysUserDAO.update(null, onlineLambdaUpdateWrapper);

            //设置离线状态
            LambdaUpdateWrapper<SysUser> offlineLambdaUpdateWrapper = new LambdaUpdateWrapper<>();
            offlineLambdaUpdateWrapper.notIn(SysUser::getId, onlineUserIdList);
            offlineLambdaUpdateWrapper.set(SysUser::getUserOnlineStatus, 0);
            offlineLambdaUpdateWrapper.set(SysUser::getUpdateTime, now);
            sysUserDAO.update(null, offlineLambdaUpdateWrapper);
        }

    }

    /**
     * 批量获取用户
     */
    public Map<Long, MicroSysUserAllInfoVo> batchGetUser(List<Long> ids, int maxValue) {
        List<Long> list;
        int size = ids.size();
        int total = size / maxValue;
        if (size % maxValue != 0) {
            total += 1;
        }
        Map<Long, MicroSysUserAllInfoVo> result = new HashMap<>();
        for (int i = 0; i < total; i++) {
            if (i == total - 1) {
                maxValue = size - (i * maxValue);
            }
            list = ids.subList(0, maxValue);

            // 批量处理的方法
            Map<Long, MicroSysUserAllInfoVo> longMicroSysUserAllInfoVoMap = batchGetUser(list);
            result.putAll(longMicroSysUserAllInfoVoMap);

            list.clear();
        }
        return result;
    }

    /**
     * 批量获取用户
     */
    public Map<Long, MicroSysUserAllInfoVo> batchGetUser(List<Long> ids) {
        com.telit.common.core.utils.Result<Map<Long, MicroSysUserAllInfoVo>> selectUserContainDeptAndRoleWithBatchIdsResult = remoteUpmsService.selectUserContainDeptAndRoleWithBatchIds(
                ids, true);
        return FeignUtils.unwrap(selectUserContainDeptAndRoleWithBatchIdsResult);
    }

}
